package nl.nhl.idp.Components;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;

/**
 * Handles the steering with the tablet/phone
 * @author Mark van der Wal
 *
 */
public class Accelerometer implements SensorEventListener
{
	// constants
	private static float FILTERFACTOR = 0.8f;
	
	// data members
	private AccelerometerListener listener;
	private SensorManager mSensorManager;
	private Sensor mAccelerometer;
	private float gravity[];
	private Context mContext;
	
	/**
	 * Constructor
	 * @param context this class is called in
	 */
	public Accelerometer(Context context)
	{
		// initialize gravity vector
        gravity = new float[3];
        gravity[0] = 0;
        gravity[1] = 0;
        gravity[2] = 0;
        
        // initialize sensor
        mContext = context;
	}
	
	/**
	 * Register the sensor listener
	 */
	public void register()
	{
        mSensorManager = (SensorManager)mContext.getSystemService(Context.SENSOR_SERVICE);
        mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
	}
	
	/**
	 * Unregister the sensor listener
	 */
	public void unregister()
	{
        mSensorManager = (SensorManager)mContext.getSystemService(Context.SENSOR_SERVICE);
        mSensorManager.unregisterListener(this);
	}
	
	/**
	 * Sets the listener for the steering wheel
	 * @param listener we use 
	 */
	public void setOnMoveListener(AccelerometerListener listener)
	{
		this.listener = listener;
	}

	/**
	 * We do not handle the accuracy changed event
	 */
	public void onAccuracyChanged(Sensor sensor, int accuracy)  
	{ 
		// do nothing 
	}
	
	/**
	 * When the sensor notices changes we handle them
	 */
	public void onSensorChanged(SensorEvent event) 
	{			
		// check if the sensor is a accelerometer
		if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
		{				    
		    // iterate over all 3 axis and low pass filter them
		    for(int i = 0 ; i  <3; i++)
		    {
		    	float value = (event.values[i] / SensorManager.STANDARD_GRAVITY);
		    	
		    	if(value > 0.01f || value < -0.01f) //remove random zero readings
		    	{
		    		gravity[i] = FILTERFACTOR * value + (1 - FILTERFACTOR) * gravity[i];
		    		
		    		// keeping the values between -1 and 1
		    		gravity[i] = Clamp(gravity[i], -1.0f, 1.0f);
		    	}
		    }
		    
		    // check for listener
		    if(listener != null)
		    {
		    	// X, Y, Z 
		    	listener.onMoved(gravity[0], gravity[1], gravity[2]);
		    }
		}
	}
	
	/**
	 * For clamping values

	 * @return
	 */
	private float Clamp(float value, float min, float max)
	{
		return (value < min) ? min : (value > max) ? max : value;
	}
}
